package com.gpt.article.controller;

import java.io.File;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import chatgpt.ChatGPT;
import chatgpt.api.Api;
import chatgpt.entity.BaseResponse;
import chatgpt.entity.billing.SubscriptionData;
import chatgpt.entity.billing.UseageResponse;
import chatgpt.entity.chat.Message;
import chatgpt.exception.ChatException;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.poi.excel.ExcelReader;
import com.alibaba.fastjson.JSON;
import com.gpt.article.controller.websocket.WebSocketUsers;
import com.gpt.article.domain.AContent;
import com.gpt.article.domain.GptTopicTitle;
import com.gpt.article.domain.TxtClassify;
import com.gpt.article.service.IAContentService;
import com.gpt.article.service.impl.GptFunPromptsServiceImpl;
import com.gpt.article.service.impl.GptGenArticleTaskServiceImpl;
import com.gpt.article.service.impl.QContentServiceImpl;
import com.gpt.article.service.impl.taskHandle.testTask.ClassTaskTest;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
import io.reactivex.Single;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.gpt.article.domain.QContent;
import com.gpt.article.service.IQContentService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;

/**
 * 模型比较Controller
 * 
 * @author zhuzi
 * @date 2024-02-25
 */
@RestController
@RequestMapping("/article/qContent")
public class QContentController extends BaseController
{
    @Autowired
    private IQContentService qContentService;

    @Autowired
    private IAContentService aContentService;
    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private GptGenArticleTaskServiceImpl gptGenArticleTaskServiceImpl;

    @Autowired
    private QContentServiceImpl qContentServiceiml;

    @Autowired
    private GptFunPromptsServiceImpl gptFunPromptsServiceImpl;
    private OkHttpClient okHttpClient;
    private Api apiClient;
    /**
     * 查询模型比较列表
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:list')")
    @GetMapping("/list")
    public TableDataInfo list(QContent qContent)
    {
        startPage();
        List<QContent> list = qContentService.selectQContentList(qContent);
        return getDataTable(list);
    }

    /**
     * 导出模型比较列表
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:export')")
    @Log(title = "模型比较", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, QContent qContent)
    {
//        qContent.setGenStatus("2");
        List<QContent> list = qContentService.selectQContentList(qContent);

        Map<String,Object> map = null;
        List<Map<String,Object>> mapList = new ArrayList<Map<String,Object>>();
        List<AContent> aContents = new ArrayList<AContent>();;

        loop1:for(QContent qc :list){
            map = new LinkedHashMap<String,Object>();
            map.put("prompts",qc.getPrompts());
            aContents = qc.getaContents();

            loop2:for(AContent aContent:aContents){
                if("1".equals(aContent.getQpType())){
                    continue loop2;
                }
                String modelName = aContent.getModelName();
                String acontent  = aContent.getaContent();
                //导出只获取一个
                if(map.get(modelName)==null){
                    map.put(modelName,acontent);
                }
            }
            mapList.add(map);
        }

//        ExcelUtil<QContent> util = new ExcelUtil<QContent>(QContent.class);
//        ExcelUtil<HashMap> util = new ExcelUtil<>(HashMap.class);
        exportExcel(response, mapList);
//        util.exportExcel(response, mapList, "模型比较数据");
    }

    private void exportExcel(HttpServletResponse response, List<Map<String, Object>> list) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("sheet1");
        //表头
        XSSFRow headRow = sheet.createRow(0);

        //取List的第一个元素进行遍历，找出所有key作为表头
        Iterator<Map.Entry<String, Object>> iterator = list.get(0).entrySet().iterator();
        int i = 0;
        //用于数据行查找
        List<Object> headRowData = new ArrayList<>();

        List<String> keys = list.stream()
                .flatMap(map -> map.keySet().stream())
                .distinct()
                .collect(Collectors.toList());

        for(String li:keys){
            String next = li;
            //设置表头
            headRow.createCell(i).setCellValue(new XSSFRichTextString(next));
            headRowData.add(next);
            i++;
        }

//        while (iterator.hasNext()) {
//            String next = iterator.next().getKey();
//            //设置表头
//            headRow.createCell(i).setCellValue(new XSSFRichTextString(next));
//            headRowData.add(next);
//            i++;
//        }
        //列表
        int rowNUm = 1;
        for (Map<String, Object> dataMap : list) {
            //创建数据行
            XSSFRow dataRow = sheet.createRow(rowNUm);
            for (int j = 0, size = headRowData.size(); j < size; j++) {
                //设置数据
                String headData = String.valueOf(dataMap.get(headRowData.get(j)));
                if("null".equals(headData) || headData == "null"){
                    headData = "";
                }
                dataRow.createCell(j).setCellValue(headData);
            }
            rowNUm++;
        }
        //数据导出
        response.setContentType("application/octet-stream;charset=UTF-8");
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("excelName.xlsx", "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
        }
    }


    /**
     * 获取模型比较详细信息
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return success(qContentService.selectQContentById(id));
    }

    /**
     * 新增模型比较
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:add')")
    @Log(title = "模型比较", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody QContent qContent)
    {
        return toAjax(qContentService.insertQContent(qContent));
    }

    /**
     * 修改模型比较
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:edit')")
    @Log(title = "模型比较", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody QContent qContent)
    {
        return toAjax(qContentService.updateQContent(qContent));
    }

    /**
     * 删除模型比较
     */
    @PreAuthorize("@ss.hasPermi('article:qContent:remove')")
    @Log(title = "模型比较", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        return toAjax(qContentService.deleteQContentByIds(ids));
    }
    /**
     * 删除模型回答
     */
    @PreAuthorize("@ss.hasPermi('article:aContent:remove')")
    @Log(title = "删除模型回答", businessType = BusinessType.DELETE)
    @DeleteMapping("/delAcontent/{id}")
    public AjaxResult removeAcontent(@PathVariable Long id)
    {
        return toAjax(aContentService.deleteAContentById(id));
    }


    /**
     * 批量上传待提问内容
     * @param file
     * @return
     * @throws Exception
     */
    @Log(title = "上传待提问内容", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file,String useModels ) throws Exception {
//
        String operName = getUsername();
        // 上传文件路径
        String filePath = RuoYiConfig.getUploadPath();
        // 上传并返回新文件名称
        String fileName = FileUploadUtils.upload(filePath, file);
        String url = serverConfig.getUrl() + fileName;
        AjaxResult ajax = AjaxResult.success();
        ajax.put("url", url);
        ajax.put("fileName", fileName);
        ajax.put("newFileName", FileUtils.getName(fileName));
        ajax.put("originalFilename", file.getOriginalFilename());
        System.out.println(filePath + "/" + fileName);
        //解析文件
        System.out.println(filePath + "--");
        String tmpfilePath = filePath + fileName.replaceAll("/profile/upload", "");
        File excelFile = new File(tmpfilePath);
        ExcelReader reader = cn.hutool.poi.excel.ExcelUtil.getReader(excelFile);
        List<Map<String, Object>> maps = reader.readAll();
        QContent qContent = null;
        for(Map map:maps){
            Set<String> set = map.keySet();
            for(String key:set){
                String title  =String.valueOf( map.get(key));
                qContent = new QContent();
                qContent.setPrompts(title);
                qContent.setGenStatus("0");
                qContent.setModelCodes(useModels);
                qContentService.insertQContent(qContent);
                break;
            }
        }
        reader.close();
        return success("成功");
    }


    /**
     * 生成问题答案
     *
     * @param map
     *   洗稿参数条件
     */
    @Log(title = "执行全量生成任务", businessType = BusinessType.GEN)
    @PostMapping("/tartGenAll")
    public AjaxResult tartGenAll(@RequestBody Map<String,Object> map)
    {
        QContent qContent = new QContent();
        BeanMap beanMap = BeanMap.create(qContent);
        beanMap.putAll(map);
        String acc = SecurityUtils.getUsername();
        qContentService.genManyContent(qContent,acc,map);
        return success(true);
    }
    /**
     * 生成问题答案
     * @param map
     * @return
     * @throws Exception
     */
    @Log(title = "生成内容", businessType = BusinessType.GEN)
//    @GetMapping("/startGen/{ids}")
    @PostMapping("/startGen")
    public AjaxResult startGen(@RequestBody  Map<String,Object> map){
        String acc = SecurityUtils.getUsername();
        String idstr = String.valueOf(map.get("ids"));
        String idst[] =  idstr.split(",");
        Long[] ids = stringToLong(idst);
        qContentService.genGptContent(ids,acc,map);
        return success(true);
    }

//    genContentOne
@Log(title = "发送内容生成", businessType = BusinessType.GEN)
//    @GetMapping("/startGen/{ids}")
@PostMapping("/genContentOne")
public AjaxResult genContentOne(@RequestBody  Map<String,Object> map){
    String acc = SecurityUtils.getUsername();
    List<String> usemodelCodes = (List)map.get("usemodelCode");
    String prompts_input = String.valueOf(map.get("prompts_input"));
    qContentService.genContentOne(usemodelCodes,prompts_input,acc);
    return success(true);
}


    @Log(title = "发送内容追问生成", businessType = BusinessType.GEN)
//    @GetMapping("/startGen/{ids}")
    @PostMapping("/genAddPrompts")
    public AjaxResult genAddPrompts(@RequestBody  Map<String,Object> map){
        String acc = SecurityUtils.getUsername();
        qContentService.genAddPrompts(map,acc);
        return success(true);


    }

//    gptFunPromptsServiceImpl

//    @Log(title = "重试失败，生成为空的答案", businessType = BusinessType.GEN)
////    @GetMapping("/startGen/{ids}")
//    @GetMapping("/getSetModelInfo/{ids}")
//    public AjaxResult getSetModelInfo(@PathVariable String ids)
//    {
//        return success(gptFunPromptsServiceImpl.selectGptFunPromptsByName("chat-comparer"));
//    }








    @Log(title = "重试失败，生成为空的答案", businessType = BusinessType.GEN)
//    @GetMapping("/startGen/{ids}")
    @PostMapping("/genRetryAContent")
    public AjaxResult genRetryAContent(@RequestBody  Map<String,Object> map){
        String acc = SecurityUtils.getUsername();
//        aContentService
        String  qContentId = String.valueOf(map.get("qContentId"));
        String  aContentId = String.valueOf(map.get("aContentId"));
        qContentId = qContentId.replaceAll("\\[","").replaceAll("\\]","").replaceAll(" ","").trim();
        aContentId = aContentId.replaceAll("\\[","").replaceAll("\\]","").replaceAll(" ","").trim();
        AContent aContent = new AContent();
        if(StringUtils.isNotEmpty(qContentId)&&!"null".equals(qContentId)){
            aContent.setqContentId(Long.valueOf(qContentId));
        }
        aContent.setaContent("");
        List<AContent>  aContents = aContentService.selectEmptyAContentList(aContent);
        logger.info("存在未生成回答数量："+aContents.size());
        if(aContents.size()==0){
           return warn("不存在空白回答，无需重试！");
        }
        seedTxt(aContents.size(),0,"start","0");

        List<QContent> qContents = new ArrayList<QContent>();
        Map<Long, List<String>> aModeGroup = aContents.stream()
                .collect(Collectors.groupingBy(
                        AContent::getqContentId,
                        Collectors.mapping(AContent::getModelCode, Collectors.toList())
                ));
        String finalAContentId = aContentId;
        aModeGroup.forEach((key, value) -> {
            System.out.println("Key = " + key + ", Value = " + value);
//            List<String> modeNames = value;
            String result = String.join(",", value);
            QContent qContent = qContentService.selectQContentById(key);
            qContent.setModelCodes(result);
//            qContent.setAcontentId();
            if(StringUtils.isNotEmpty(finalAContentId)&&!"null".equals(finalAContentId)){
                qContent.setAcontentId(Long.valueOf(finalAContentId));
            }
            qContents.add(qContent);
        });

        qContentServiceiml.genStart(qContents,acc);

        logger.info("重试空白回答完成");
        seedTxt(aContents.size(),aContents.size(),"end","0");
        return success(true);
    }


    @Log(title = "重试失败，生成为空的答案", businessType = BusinessType.GEN)
    @PostMapping("/getModelSet")
    public AjaxResult getModelSet(@RequestBody String ps)
    {
        return success(gptFunPromptsServiceImpl.selectGptFunPromptsByName("chat-comparer"));

    }

    @Log(title = "查询余额", businessType = BusinessType.GEN)
//    @GetMapping("/startGen/{ids}")
    @PostMapping("/showBanlance")
    public AjaxResult showBanlance(@RequestBody  String map){
        BigDecimal bacle = new ChatGPT().balance("sk-9DyjI9zAVYsPSVrIF2A97101B1784f2aB4B18e727e5478D9");
        return success(bacle);
    }

    public Long[] stringToLong(String[] strings) {
        if (strings == null || strings.length < 1) {
            return null;
        }
        Long[] longs = new Long[strings.length];
        for (int i = 0; i < strings.length; i++) {
            String longidstr = strings[i].replaceAll("\\[","")
                    .replaceAll("\\]","").replaceAll(" ","").trim();
            Long str = Long.valueOf(longidstr);
            longs[i] = str;
        }
        return longs;
    }


    /**
     * 生成问题答案
     * @param allNum
     *  总数
     * @param comnum
     * 完成数
     * @param statustr
     * 状态
     * @param processstr
     * 进程百分比
     * @return
     */
    public Boolean seedTxt(Integer allNum,Integer comnum,String statustr,String processstr){
        String  message = "任务提示:\n正在重试空白回答,总数："+allNum+"，" +
                "完成数："+comnum+"个。(如果一直卡在这个界面可以尝试刷新页面)";
        Map<String,Object> msgmap = new HashMap<String,Object>();
        msgmap.put("message",message);
        msgmap.put("percentage",comnum/allNum);
        msgmap.put("acontentId",null);
        msgmap.put("status",statustr);

        String  jsonString = JSON.toJSONString(msgmap);
        WebSocketUsers.sendMessageToUsersByText(jsonString);
        return true;
    }


}
